package com.example.mysaat.service_menu_manual_test.allActivities;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.example.mysaat.R;
import com.example.mysaat.handle_utils.CameraOrientationListener;
import com.example.mysaat.handle_utils.CustomCameraSize;
import com.example.mysaat.handle_utils.FocusImageView;
import com.example.mysaat.handle_utils.ScreenUtils;
import com.example.mysaat.handle_utils.SquareCameraPreview;
import com.example.mysaat.service_menu_manual_test.Listeners.MyFailOnclickListener;
import com.example.mysaat.service_menu_manual_test.Listeners.MyPassOnclickListener;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

public class Camera_MainActivity extends Activity implements SurfaceHolder.Callback, Camera.PictureCallback  {

    private SquareCameraPreview surfaceView;
    private FocusImageView focusImageView; //对焦的图片
    private SurfaceHolder surfaceHolder; // 提供访问，控制surfaceView背后的surface的相关方法
    private Camera camera;
    private int cameraPosition=0;       //0:后置，1：前置
    private int PICTURE_SIZE_MAX_WIDTH;  //照片的最大宽度
    private int PICTURE_SIZE_MAX_HIGHT;  //照片的最大高度
    private boolean isPreviewing = false; //控制拍照后的预览效果
    private int cameraCount; // 摄像头的个数
    private CameraOrientationListener cameraOrientationListener;    //相机方向监听器
    private int rorationCamera;  //相机的旋转
    private int displayDegree;   //相机的选择角度
    private String imageName;    //创建图片的名字
    private String imageFolderName; //存放图片的位置
    private File imageFolder;
    private TextView tv;
    private Button fail_btn,retry_btn,pass_btn;
    private LinearLayout linearLayout;
    private static final String TAG = "Camera_MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_camera__main);

        PICTURE_SIZE_MAX_HIGHT = ScreenUtils.getScreenHeight(this);
        PICTURE_SIZE_MAX_WIDTH = ScreenUtils.getScreenWidth(this);
        init();
        initContent();
    }

    private void init(){
        tv = findViewById(R.id.camera_main_size_tv);
        fail_btn = findViewById(R.id.camera_main_fail);
        pass_btn = findViewById(R.id.camera_main_pass);
        retry_btn = findViewById(R.id.camera_main_retry);
        surfaceView = findViewById(R.id.texture);
        focusImageView = findViewById(R.id.focus_image_view);
        linearLayout = findViewById(R.id.camera_main_judge_ll);
    }

    private void initContent(){
        fail_btn.setOnClickListener(new MyFailOnclickListener(Camera_MainActivity.this,null));
        pass_btn.setOnClickListener(new MyPassOnclickListener(Camera_MainActivity.this,null));
        retry_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                linearLayout.setVisibility(View.GONE);
                surfaceView.mIsFinished = true;
                isPreviewing = false;
            }
        });
        cameraOrientationListener = new CameraOrientationListener(this);
        cameraOrientationListener.enable();
        surfaceHolder = surfaceView.getHolder();
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
        surfaceHolder.addCallback(this);

        surfaceView.setFocusImageView(focusImageView);  //设置焦点图像的视图
        surfaceView.setAutoFocusCallBack(autoFocusCallback);
        surfaceView.setCameraActivity(Camera_MainActivity.this);
        cameraCount = Camera.getNumberOfCameras();// 获得摄像头的个数
    }

    public void takePicture(){
        isPreviewing = true;
        //记住旋转的方向
        cameraOrientationListener.rememberOrientation();
        try {
        camera.takePicture(null,null,null,Camera_MainActivity.this);
        linearLayout.setVisibility(View.VISIBLE);
        }catch (Exception e){
            Log.d(TAG, "take picture encounter error");
        }
    }



    @Override
    protected void onPause() {
        super.onPause();
        cameraOrientationListener.disable();
        stopPreview();
    }

    private final Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback(){
        @Override
        public void onAutoFocus(boolean success, Camera camera) {
            //聚焦之后根据结果修改图片
            if(success){
                surfaceView.focusImageView.onFoucusSuccess();
            }else{
                surfaceView.focusImageView.onFocusFailed();
            }
        }
    };

    /**
     * 设置聚焦状态
     *
     * @param b
     */
    private void setFocusStatus(boolean b) {
        Camera.Parameters parameters = camera.getParameters();
        if (parameters.getSupportedFocusModes().contains(
                Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE) && b) {
            parameters
                    .setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);//照连续聚焦
        } else if (parameters.getSupportedFocusModes().contains(
                Camera.Parameters.FOCUS_MODE_AUTO)) {
            parameters
                    .setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);//自动焦点
        }
        camera.setParameters(parameters);
    }

    /**
     * 得到相机的感光度（ISO）
     * @param param
     * @return
     */
    public String[] getAllISOValuses(Camera.Parameters param) {
        String flat = param.flatten();
        String[] isoValues = null;
        String values_keyword = null;
        String iso_keyword = null;
        if (flat.contains("iso-values")) {
            // most used keywords
            values_keyword = "iso-values";
            iso_keyword = "iso";
        } else if (flat.contains("iso-mode-values")) {
            // google galaxy nexus keywords
            values_keyword = "iso-mode-values";
            iso_keyword = "iso";
        } else if (flat.contains("iso-speed-values")) {
            // micromax a101 keywords
            values_keyword = "iso-speed-values";
            iso_keyword = "iso-speed";
        } else if (flat.contains("nv-picture-iso-values")) {
            // LG dual p990 keywords
            values_keyword = "nv-picture-iso-values";
            iso_keyword = "nv-picture-iso";
        }
        // add other eventual keywords here...
        if (iso_keyword != null) {
            // flatten contains the iso key!!
            String iso = flat.substring(flat.indexOf(values_keyword));
            iso = iso.substring(iso.indexOf("=") + 1);
            if (iso.contains(";")) iso = iso.substring(0, iso.indexOf(";"));
            isoValues = iso.split(",");
        } else {
            isoValues = null; // iso not supported in a known way
        }
        return isoValues;
    }

    private void stopPreview(){
        if (camera != null) {
            camera.stopPreview();
            camera.release();
            camera = null;
        }
    }

    /**author zhao guang fei
     *the method will storage the picture captured by camera into specific path
     * @param picture picture captured by camera
     */
    private void storePicture(Bitmap picture){
        imageName = new SimpleDateFormat("yyyyMMddhhMMss").format(new Date());
        File finalImagePath = new File(imageFolderName,imageName+".jpg");
        if(finalImagePath.exists()){
            finalImagePath.delete();
        }

        try {
            finalImagePath.createNewFile();
            FileOutputStream outputStream = new FileOutputStream(finalImagePath);
            if(picture.compress(Bitmap.CompressFormat.JPEG,100,outputStream)){
                outputStream.flush();
                outputStream.close();
            }
            updateAlbum(finalImagePath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * after taking photo ,update photo album
     */
    public void updateAlbum(File path){
        Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        Uri uri = Uri.fromFile(path);
        intent.setData(uri);
        sendBroadcast(intent);
    }

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
        rorationCamera = cameraOrientationListener.getmRememberNormalOrientation();
        Bitmap bitmap = decodeSampledBitmapFromByte(data); // 将照片从字节流转成图片
        Camera.CameraInfo info = new Camera.CameraInfo();
//        storePicture(rorateImage(displayDegree,bitmap));
        setPreview(false);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        try {
            if (cameraPosition == 0) {
                camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
            } else {
                camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
            }

            surfaceView.setCamera(camera);
            camera.setPreviewDisplay(holder); // 设置 holder
        } catch (Exception e) {
            displayFrameworkBugMessageAndExit();
            camera = null;
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        setPreview(true);
        if (surfaceHolder.getSurface() == null) {
            return;
        }

        try {
            camera.setPreviewDisplay(surfaceHolder);
        } catch (IOException e) {
            e.printStackTrace();
        }
//        setPreview(true);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        setPreview(false);
        stopPreview();
    }

    /**
     *设置白平衡
     * @param parameters
     */
    private void setWhiteBalance(Camera.Parameters parameters){
        parameters.setPictureFormat(PixelFormat.JPEG);
        //设置白平衡
        try {
            parameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);

            try {
                String[] isoves = getAllISOValuses(parameters);
                if (null != isoves) {
                    for (int i = 0; i < isoves.length; i++) {
                        if ("auto".equals(isoves[i])) {
                            parameters.set("iso", (String) isoves[i]);
                            break;
                        }
                    }
                }
            } catch (Exception e) {
                Log.e("e", e.toString());
            }
        } catch (Exception e) {
            Toast.makeText(this, "平衡模式设置异常", Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 未打开相机提示信息
     */
    private void displayFrameworkBugMessageAndExit() {
        new AlertDialog.Builder(this).setTitle("提示")
                .setMessage("打开相机失败，请确认权限以及相机是否可用！")
                .setPositiveButton("确定", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        finish();
                    }
                }).show();
    }

    /**author: zhaoguangfei
     * according to width and height of screen to set suitable frame of picture
     * @param parameters
     */
    private void setFitPictureSize(Camera.Parameters parameters){
        if (Build.VERSION.SDK_INT >= 24) {//7.0版本
            List<Camera.Size> preSizes = parameters.getSupportedPreviewSizes();
            Camera.Size bestPreviewSize = CustomCameraSize.getInstance().getPreviewSize(preSizes,
                    PICTURE_SIZE_MAX_WIDTH, PICTURE_SIZE_MAX_HIGHT);
            if (bestPreviewSize != null) {
                parameters.setPreviewSize(bestPreviewSize.width,
                        bestPreviewSize.height);
                tv.setText(bestPreviewSize.height+"x"+bestPreviewSize.width);
            }
            List<Camera.Size> picSizes = parameters.getSupportedPictureSizes();
            Camera.Size bestPicSize = CustomCameraSize.getInstance().getPictureSize(picSizes,
                    PICTURE_SIZE_MAX_WIDTH, PICTURE_SIZE_MAX_HIGHT);
            if (bestPicSize != null) {
                parameters.setPictureSize(bestPicSize.width,
                        bestPicSize.height);

            }
            /**--------------------------*/
            findViewById(R.id.all).postInvalidate();
            /***-------------------------********/

        } else {
            CustomCameraSize.getInstance().getPictureAndPreViewSize(parameters,
                    PICTURE_SIZE_MAX_WIDTH, PICTURE_SIZE_MAX_HIGHT);
            List<Camera.Size> preSizes = parameters.getSupportedPreviewSizes();
            Camera.Size bestPreviewSize = CustomCameraSize.getInstance().getPreviewSize(preSizes,
                    PICTURE_SIZE_MAX_WIDTH, PICTURE_SIZE_MAX_HIGHT);
            if (bestPreviewSize != null)
                parameters.setPreviewSize(bestPreviewSize.width,
                        bestPreviewSize.height);
            parameters.setPictureSize(parameters.getPreviewSize().width,
                    parameters.getPreviewSize().height);
            tv.setText(bestPreviewSize.height+"x"+bestPreviewSize.width);
        }
    }

    /**author  Zhao Guang Fei
     * according to the state of btn checked, state: (true) camera executes continuously auto focus,
     * state:(false) camera executes auto focus
     * @param parameters {#link Camera.Parameters} the parameters of camera,however it's an Object
     */
    private void autoFocus(Camera.Parameters parameters){
            if (parameters.getSupportedFocusModes().contains(
                    Camera.Parameters.FOCUS_MODE_AUTO)) {
                parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);// 自动焦点
            }
    }

    /**author  Zhao Guang Fei
     * Android API: Display Orientation Setting
     * Just change screen display orientation,
     * the rawFrame data never be changed.
     */
    private void setCameraDisplayOrientation(Activity activity, int cameraId, Camera camera) {
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(cameraId, info);
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation(); // 获取屏幕旋转的角度
        int degrees = 0;
        switch (rotation) {
            case Surface.ROTATION_0:
                degrees = 0;
                break;
            case Surface.ROTATION_90:
                degrees = 90;
                break;
            case Surface.ROTATION_180:
                degrees = 180;
                break;
            case Surface.ROTATION_270:
                degrees = 270;
                break;
        }

        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            displayDegree = (info.orientation + degrees) % 360;
            displayDegree = (360 - displayDegree) % 360;  // compensate the mirror
        } else {
            displayDegree = (info.orientation - degrees + 360) % 360;
        }
        camera.setDisplayOrientation(displayDegree);
    }

    /**
     * 从字节中解密图片
     * @param bitmapBytes
     * @return
     */
    public Bitmap decodeSampledBitmapFromByte(byte[] bitmapBytes) {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        options.inMutable = true;
        options.inBitmap = BitmapFactory.decodeByteArray(bitmapBytes, 0,
                bitmapBytes.length, options);
        // Calculate inSampleSize
        options.inSampleSize = calculateInSampleSize(options, ScreenUtils.getScreenWidth(this),
                ScreenUtils.getScreenHeight(this));
        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false; // If set to true, the decoder will
        options.inPurgeable = true; // Tell to gc that whether it needs free
        options.inInputShareable = true; // Which kind of reference will be used

        return BitmapFactory.decodeByteArray(bitmapBytes, 0,
                bitmapBytes.length, options);
    }

    private Bitmap rorateImage(int angle,Bitmap bitmap){
        Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
        Camera.getCameraInfo(cameraPosition,cameraInfo);
        //旋转图片
        Matrix metrix = new Matrix();
        if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            metrix.postScale(-1,1); //(-1,1)左右翻转  (1,-1)上下翻转
        }
        metrix.postRotate(angle);
        //创建新的图片
        Bitmap resizeBitmap = Bitmap.createBitmap(bitmap,0,0,bitmap.getWidth(),bitmap.getHeight(),metrix,true);
        return resizeBitmap;
    }

    /**
     *  压缩图片
     * @param options
     * @param reqWidth
     * @param reqHeight
     * @return
     */
    public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        int initialInSampleSize = computeInitialSampleSize(options, reqWidth, reqHeight);
        int roundedInSampleSize;
        if (initialInSampleSize <= 4) {
            roundedInSampleSize=initialInSampleSize;
        } else {
            roundedInSampleSize = (initialInSampleSize + 3) / 4 * 2;
        }
        return roundedInSampleSize;
    }

    /**
     * 方法名称: calculateInSampleSize
     * <br/>方法详述: 智能计算压缩值
     * <br/>参数:
     * <br/>返回值:  得到智能计算压缩值
     * <br/>异常抛出 Exception:
     * <br/>异常抛出 NullPointerException:
     */
    private static int computeInitialSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final double height = options.outHeight;
        final double width = options.outWidth;

        final long maxNumOfPixels = reqWidth * reqHeight;
        final int minSideLength = Math.min(reqHeight, reqWidth);

        int lowerBound = (maxNumOfPixels < 0) ? 1 : (int) Math.ceil(Math
                .sqrt(width * height / maxNumOfPixels));
        int upperBound = (minSideLength < 0) ? 128 : (int) Math.min(
                Math.floor(width / minSideLength),
                Math.floor(height / minSideLength));

        if (upperBound < lowerBound) {
            // return the larger one when there is no overlapping zone.
            return lowerBound;
        }
        if (maxNumOfPixels < 0 && minSideLength < 0) {
            return 1;
        } else if (minSideLength < 0) {
            return lowerBound;
        } else {
            return upperBound;
        }
    }

    /**
     * 设置相机参数
     */
    private void setupCamera() {
        // Never keep a global parameters
        Camera.Parameters parameters = camera.getParameters();
        //设置白平衡
        setWhiteBalance(parameters);
        //设置相机的角度
        setCameraDisplayOrientation(this, cameraPosition, camera);
        // 先找最合适的照片尺寸
        // 根据屏幕长宽比
        setFitPictureSize(parameters);
        // 判断是否勾选中聚焦
        autoFocus(parameters);

        setFlashLight(parameters);
        camera.setParameters(parameters);
    }

    /**
     * 设置闪光灯
     */

    private void setFlashLight(Camera.Parameters parameters){
        if(!this.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)){
            Toast.makeText(this,"你的设备不支持闪光灯",Toast.LENGTH_SHORT).show();
            return;
        }
        parameters.setFlashMode(Camera.Parameters.FLASH_MODE_ON);
    }

    /**
     * 设置预览或停止预览
     * @param is
     */
    private void setPreview(boolean is) {
        if (is) {
            if (!isPreviewing) {
                setupCamera();
                camera.startPreview();
                isPreviewing = true;
                surfaceView.isPreviewing = is;
            }

        } else {
            if (isPreviewing && camera != null)
                camera.stopPreview();
            Log.d(TAG, "setPreview: "+isPreviewing);
//            isPreviewing = false;
            surfaceView.isPreviewing = is;
        }
    }


    private final Camera.AutoFocusCallback autoFocusCallBack = new Camera.AutoFocusCallback(){

        @Override
        public void onAutoFocus(boolean b, Camera camera) {

        }
    };
}
